#include "InstancedOrbs.h"

//Complete forward declarations. 
#include "StaticInstancedModel.h"
#include "GraphicsInterface.h"

//Needed for the StaticModelBasicMaterial struct
#include "StaticModel.h"

//Include globals to get folder directories
#include "Globals.h"

InstancedOrbs::InstancedOrbs(ID3D11Device* device, unsigned initialCount)
{
	//Output helpful string...
	OutputDebugStringW(L"Creating Instanced Orbs (Collectables)...\n");

	//Assert that initial count != 0. 0 would indicate an error
	assert(initialCount != 0);

	//Init pointers to NULL. 
	instOrbs = 0;

	//Create instanced model data. 
	instOrbs = new StaticInstancedModel(device, initialCount);

	//Information structure to pass when creating the orb - Eg: reflectivitiy, 
	//textures etc. 
	StaticModelBasicMaterial mat;

	//Set the models reflectivity material
	mat.Material.Ambient = XMFLOAT4(0.6f, 0.6f, 0.6f, 1.0f);
	mat.Material.Diffuse = XMFLOAT4(0.4f, 0.4f, 0.4f, 0.5f);   //Semi-transparent
	mat.Material.Specular = XMFLOAT4(0.3f, 0.3f, 0.3f, 64.0f);
	mat.Material.Reflection = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f); //No reflection. 

	//Semi-Transparent. 
	mat.IsOpaque = false;

	//Texture file paths.
	mat.TextureMapFilePath = DEFAULT_TEXTURE_FOLDER_PATH L"rock01_diffuse.dds";
	mat.NormalMapFilePath = DEFAULT_TEXTURE_FOLDER_PATH L"rock01_normal.dds";
	
	//Ue texture map and normal map.
	mat.UseTextureMap = true;
	mat.UseNormalMap = true;

	//Load model data. 
	//instOrbs->CreateGeoSphere(INST_ORB_RADIUS, INST_ORB_SUBDIVISION, 
	//	&mat, device);
	instOrbs->CreateSphere(INST_ORB_RADIUS, INST_ORB_SLICE_COUNT, INST_ORB_STACK_COUNT, 
		&mat, device);
};

InstancedOrbs::~InstancedOrbs()
{
	//Delete the orb
	SafeDelete(instOrbs);
}

void InstancedOrbs::SetOrbLocations(const std::vector<XMFLOAT3>&locations)
{
	//Ensure we are not passing more locations than we have allocated.
	if (locations.size() > instOrbs->ReturnMaxInstanceCount())
	{
		OutputDebugStringW(L"InstancedOrbs Error - Trying to create too many orbs...\n");
		while(1){}
	}

	//Create instanced data.
	for (unsigned i = 0; i < locations.size(); i++)
	{
		//Location of each orb - note, no rotations/scale. 
		InstanceData iData;
		iData.Active = true;
		iData.Pos = locations[i];

		//Displace on Y
		iData.Pos.y += INST_ORB_DISPLACEMENT_Y;

		//No rotation or scale. 
		iData.Rot = XMFLOAT3(0.0f, 0.0f, 0.0f);
		iData.Scale = XMFLOAT3(1.0f, 1.0f, 1.0f);

		//Create the instance.
		instOrbs->CreateInstance(iData);

		//temp hitbox used to add to vector
		AABB temphit;

		// Create bounding box for each instance
		temphit.CenterW = locations[i];

		XMFLOAT3 temp = instOrbs->GetAABBL().Extents;

		temp.x *= (iData.Scale.x*2);
		temp.y *= (iData.Scale.y*2);
		temp.z *= (iData.Scale.z*2);

		temphit.ExtentsW = temp;

		HitBox.push_back(temphit);
	}
}

XMFLOAT3 InstancedOrbs::GetInstancePosition(unsigned instanceID)
{
	//Get data from static instanced model 
	InstanceData* data = instOrbs->GetInstanceData(instanceID);

	//Return location.
	return data->Pos;
}

void InstancedOrbs::UpdateInstance(unsigned instanceID,
	XMFLOAT3 position, bool isActive)
{
	//Get previous data
	InstanceData* data = instOrbs->GetInstanceData(instanceID);

	//Update pos and active flag
	data->Pos = position;
	data->Active = isActive;
}

void InstancedOrbs::AddToBatch(GraphicsInterface* gi)
{
	//Add to the batch if GI is not NULL. 
	if (gi)
		gi->AddModelToBatch(instOrbs);
	else
	{
		OutputDebugStringW(L"InstancedOrbs Error - Graphics Interface == NULL\n");
		while(1){}
	}
}

AABB InstancedOrbs::GetHitBox(unsigned instanceID)
{
	return HitBox[instanceID];
}

// Returns whether the instanced orb is active or not.
bool InstancedOrbs::GetIsActive(unsigned instanceID)
{
	InstanceData* data = instOrbs->GetInstanceData(instanceID);

	return data->Active;
}

void InstancedOrbs::SetIsActive(unsigned instanceID,bool active)
{
	InstanceData* data = instOrbs->GetInstanceData(instanceID);

	data->Active = active;
}
